import os, re
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from utils import common
from manager.models import *
import datetime

"""
验证文件上传用的装饰器模块
views           视图
decorators      装饰器
csrf            跨站点伪造请求
csrf_exempt     跳过csrf验证
导入跳过csrf验证的装饰器模块
"""
from django.views.decorators.csrf import csrf_exempt

from django.conf import settings
# 验证器
from manager.formModel.articleForm import *


# 文章管理页面
def article(request):
    # 获取所有文章信息
    items = Article.objects.all()
    # 获取后台菜单
    menu = settings.MENU
    # 获取信息传递到模板中
    data = {
        "user": request.session.get('user'),
        "menu": menu,
        'items': items,
        'count': items.count()
    }
    return render(request, 'backstage/article/article.html', data)


# 添加文章
def article_add(request):
    # 表单验证器   实例化 ArticleForm类返回一个对象

    articleForm = ArticleForm(request.POST)
    if request.is_ajax():
        # 验证通过时返回的是True
        if articleForm.is_valid():
            # 根据验证器的字段属性 获取验证成功的数据，返回一个字典
            data = articleForm.cleaned_data
            # 栏目id
            data['category_id'] = request.POST.get('category_id')
            # 文章热推
            data['flag'] = request.POST.get('flag')
            # 图片
            data['picture'] = request.POST.get('picture', '')
            # 发布人
            data['manager_id'] = request.session['user']['id']

            article = Article.objects.create(**data)

            # 发布附加表的相关信息
            Atricle_additional.objects.create(article=article, content=request.POST['content'])

            return JsonResponse({'msg': '添加成功！', 'code': 0, 'data': []})
        return JsonResponse({'msg': '添加失败！', 'code': 1, 'data': []})
    # 客户端第一次请求时返回的数据（打开页面的第一个响应）
    cates = Category.objects.all().values('id', 'cate_name')
    return render(request, 'backstage/article/article_add.html', {'articleForm': articleForm, 'cates': cates})


def article_edit(request):
    # get 请求,返回的都是 html
    id = request.GET.get('id')
    # id不能为空
    if not id:
        html = common.msg('要修改的文章id不能为空！')
        return HttpResponse(html)
    # 表单验证器   实例化 CategoryForm类返回一个对象
    articleForm = ArticleForm(request.POST)
    # 判断是否为ajax请求
    if request.is_ajax():
        # 判断是否验证成功
        if articleForm.is_valid():
            # 获取验证成功并且要修改的内容
            data = articleForm.cleaned_data
            # 向验证成功的数据内添加新的键值对
            # 追加栏目id
            data['category_id'] = request.POST.get('category_id')
            # 追加热推
            data['flag'] = request.POST.get('flag')
            # 追加发布人id
            data['manager_id'] = request.session['user']['id']
            # 追加要修改的图片对象
            if request.POST.get('picture', ''):
                data['picture'] = request.POST['picture']


            Article(id=id, **data).save(update_fields=data.keys())
            Atricle_additional(article_id=id,content=request.POST.get('content')).save()
            return JsonResponse({'msg': '操作成功！', 'code': 0, 'data': []})
        return JsonResponse({'msg': '操作失败！', 'code': 1, 'data': []})

    try:
        # 获取指定id的栏目信息
        data = Article.objects.get(id=id)  # 如果get查询不到数据时 会抛出异常

    except Exception as e:
        html = common.msg('修改异常！')
        return HttpResponse(html)
    cates = Category.objects.all().values('id','cate_name')
    return render(request, 'backstage/article/article_edit.html', {"article": data, "articleForm": articleForm,'cates':cates})


def article_del(request):
    """
    栏目删除
    :param request:
    :return:
    """
    id = request.GET.get('id')
    # id不能为空
    if not id:
        return JsonResponse({'msg': '请选择要操作的数据！', 'code': 1, 'data': []})
    data = Atricle_additional.objects.get(article_id=id)
    # 删除指定数据
    article = Article.objects.get(id=id)
    # 获取图片的绝对物理路径
    picture = os.path.join(settings.BASE_DIR, str(article.picture))
    # 删除物理图片
    if article.picture and os.path.isfile(picture): os.remove(picture)
    Atricle_additional.objects.get(article_id=id).delete()
    article.delete()
    return JsonResponse({'msg': '删除成功！', 'code': 0, 'data': []})


"""
上传文件视图(百度编辑器)
使用装饰器跳过csrf验证
因为页面中有两个上传图片的地方
第一个是百度的webuploader
第二个是百度的编辑器ueditor
除此之外，页面中的form表单也会提交编辑器的上传

webuploader和ueditor都会先form表单的提交一步进行提交
所以文件上传的函数中有三个判断
"""


@csrf_exempt
def fileupload(request):
    # 获取提交地址
    action = request.GET.get('action')
    # 判断action后面是否是config
    if action == 'config':
        # 获取到编辑器的初始化配置文件
        config_file = os.path.join(settings.BASE_DIR, 'static/backstage/lib/ueditor/1.4.3/php/config.json')
        """
        对配置文件进行解析
        配置文件中都是键值对，且有JS的注释/*  */
        而JS的注释在Python中并不能被识别
        所以要使用正则将正确的配置文件解析出来
        使用with方法，打开此文件，然后对其进行逐行解析
        从而得到文件内我们需要的配置代码，r为只读，不修改原文件
        """
        with open(config_file, 'r', encoding='utf-8')as f:
            # 获取到逐行读取的内容
            config = f.read()
        """
        对逐行读取出的数据进行正则匹配，获取到我们想要的数据格式
        正则模块中的sub可将字符串进行拆分
        通过转译，将/**/从读取的数据中拆分出来，替换成空，然后将值重新赋予给config
        """
        config = re.sub('\/\*[\s\S]+?\*\/', '', config)
        return HttpResponse(config)
    # 页面中有两个上传图片文件的地方，
    # 除了编辑器中的还有一个webupload
    # 我们对其也需要进行判断
    elif action == 'webupload':
        # 获取到上传的文件
        file = request.FILES['file']
        # 设置文件上传保存的目录
        upload_path = os.path.join(settings.BASE_DIR, 'art_upload', datetime.datetime.now().strftime('%Y%m%d'))
        # 判断文件上传保存的目录是否存在，如果不存在的话就新建目录
        if not os.path.exists(upload_path):
            # 创建不存在的目录
            os.makedirs(upload_path)

        # 获取到文件上传的扩展名
        ext = file.name.split('.')[-1]
        # 设置文件保存的文件名
        file_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '.' + ext
        # 拼接图片的绝对路径
        file_pos_path = os.path.join(upload_path, file_name)
        """
        a       追加，如果不存在会新建
        b       字节
        +       追加，在内容最后面开始追加，不会覆盖前面的数据
        """
        with open(file_pos_path, 'ab+') as f:
            # 使用for循环，分块添加数据
            for chunk in file.chunks():
                f.write(chunk)

        data  = {
            # 固定格式
            "jsonrpc": "2.0",
            # 拼接前台展示的图片uri
            "result": os.sep + os.path.join("uploads", datetime.datetime.now().strftime('%Y%m%d'),
                                            file_name),
            'id': 'id'
        }
        # 想页面响应一个json格式的数据
        return JsonResponse(data)
    # 判断是否是百度编辑器发送的文件
    elif action=='uploadimage':
        # 获取到上传的图片
        file = request.FILES['upfile']
        # 设置文件上传保存的目录
        upload_path = os.path.join(settings.BASE_DIR, 'art_upload', datetime.datetime.now().strftime('%Y%m%d'))
        # 判断文件上传保存的目录是否存在，如果不存在的话就新建目录
        if not os.path.exists(upload_path):
            # 创建不存在的目录
            os.makedirs(upload_path)

        # 获取到文件上传的扩展名
        ext = file.name.split('.')[-1]
        # 设置文件保存的文件名
        file_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '.' + ext
        # 拼接图片的绝对路径
        file_pos_path = os.path.join(upload_path, file_name)
        """
               a       追加，如果不存在会新建
               b       字节
               +       追加，在内容最后面开始追加，不会覆盖前面的数据
               """
        with open(file_pos_path, 'ab+') as f:
            # 使用for循环，分块添加数据
            for chunk in file.chunks():
                f.write(chunk)
        data = {
            "state": "SUCCESS",
            # 拼接前台展示的图片uri  别名
            "url": os.sep + os.path.join("uploads", datetime.datetime.now().strftime('%Y%m%d'), file_name),
            'title': file.name,
            # 原文件名
            'original': file.name,
            'type': ext,
            'size': file.size
        }
        '''
        将数据返回至前台页面
        记得要添加一个隐藏的input，将图片的路径保存下来
        设置input的name值需要与相对应的插件中负责上传的函数中设置路径
        '''
        return JsonResponse(data)
    else:
        html = common.msg('图片上传异常！')
        return HttpResponse(html)
